Assembly Language
©
Copyright Brian Brown, 1988-2000. All rights reserved.
| Notes | Home Page |
ASSEMBLY LANGUAGE PROGRAMMING, Part 8
PROGRAM MANAGEMENT TOOLS
These tools are designed to make the
process of maintaining programs easier.
MAKE
This utility is designed to ease updating of programs,
especially multiple module programs.
It works by using a list of dependencies. These dependencies illustrate the relationship between the source, include, object and executable versions of the program.
The dependencies are stored in a file called makefile.
Consider a program which has the following dependencies.
MYDBASE.EXE comprises the modules start.obj search.obj fileio.obj keybdio.obj videoio.obj
Each object file is generated from an assembler source file of the same name.
The command sequence to create the executable program is,
tasm start tasm search tasm fileio tasm keybdio tasm videoio tlink start search fileio keybdio videio, mydbase;
The dependencies and command sequences required are entered into the makefile as follows.
mydbase.exe: start.obj search.obj fileio.obj keybdio.obj videoio.obj tlink start search fileio keybdio videio, mydbase; start.obj: start.asm tasm start search.obj: search.asm tasm search fileio.obj: fileio.asm tasm fileio keybdio.obj: keybdio.asm tasm keybdio videoio.obj: videoio.asm tasm videio
The program is assembled and linked by typing
make
It works by comparing date and time stamps of the files in each dependency list. Consider the lines
keybdio.obj: keybdio.asm tasm keybdio
It compares the date/time stamp of keybdio.asm against keybdio.obj. If the object file is newer than the assembly file, it will not re-assemble.
If the assembler file has a newer date/time stamp, it will execute the command tasm keybdio to generate a new object file.
The use of make files simplifies the re-assembly by only assembling those files which have been modified.
SOURCE CODE REVISION SYSTEMS
Source code revision systems are used
to keep track of different versions of a program. It keeps a record of all the
changes made to the program.
Previous revisions can be extracted from the database, and a printout detailing the changes (time, who, line#) can be obtained.
LIBRARY MAINTENANCE
This applies to the maintenance of OBJECT code
libraries.
An Object code library contains routines which can be reused in any program. The code for the routine is extracted from the library and combined with the users object code at linking time.
Users can create their own library routines. The source files are assembled into object code then added to a library.
The following code represents a routine for placement into a Video routines library.
TITLE SetCur .CODE PUBLIC setcur setcur proc far ; set cursor to position in DX register mov ah, 2 ; dh = y co-ordinate, dl = x co-ordinate xor bh, bh int 10h ret setcur endp END
After assembling into Object code, the object code is placed into a video library using the TLIB utility.
TLIB video +setcur.obj
The following source file shows how to use the code in a library.
TITLE Libdemo .STACK 200h .CODE EXTRN setcur:far start: mov dx, 0 ; cursor 0,0 call setcur mov ax, 4c00h int 21h END start
After assembling the file Libdemo.asm, the command to link the object and library code together is,
TLINK Libdemo,libdemo.exe,libdemo.map, video
LINKERS
The assembler for 8088 PCDOS programs generates
object code files. These cannot be executed directly on the computer
system, but require further processing in order to generate a runfile. This
further process is called the linking phase.
Functions performed by a linker include:
8088 LINKER OPTIONS
The following options are used to obtain
information which is helpful in debugging programs; or generate code for 386
processors.
/m add public symbols /x no map file /s map file with segments, publics symbols and start address /t generate .COM file /v add debug info /3 386 code
The Map File Facility
If the linker is requested to generate a map
file, it will list the names, load addresses, and lengths of all segments in a
program. It also lists the names and load addresses of any groups in the
program, the start address, and messages about any errors the linker may have
encountered.
The map file generated by the linker for the program DOSCALL.ASM is,
Start Stop Length Name Class 00000H 00014H 00015H _TEXT CODE 00016H 0002AH 00015H _DATA DATA 00030H 0022FH 00200H STACK STACK Address Publics by Name Address Publics by Value Program entry point at 0000:0005
DEFINITION OF LINKING TERMS
Relocatable code is a must for multi-user and multi-tasking operating systems. The program is preceded by a header file, which the operating systems loader uses to perform relocation.
Absolute code is normally used on small single processor systems (ie, CPM), and is not suitable for multi-user environments.
Absolute code does not contain a header file used for relocation, if a header file exists, it will specify the absolute load address of the code which follows the header file.
The linker combines multiple definitions into a single overlayed segment.
The Public directive makes the variable, label or symbol in the current segment available to all other modules. It thus transforms locally defined symbols into global symbols.
The Extern directive makes a global symbols name and type known in a source file so that it may be used/referenced in that file. An extern item is a variable, label or symbol that has been declared using the public directive in another module of the program.
Example of program using public/extern directives:
Main Module NAME main .MODEL small PUBLIC exit ;defines exit as being known to other modules EXTERN print:near ;defines print as existing in another module .STACK 100h .DATA .CODE start: mov ax, @data ; Load segment location mov ds, ax ; into DS register jmp print ; goto PRINT in other module exit: mov ax, 4C00h ; call terminate function int 21h END start Task Module NAME task .MODEL small PUBLIC print ;defines print as public so it can ;be used by the calling module EXTERN exit:near ;defines exit as existing in another module ; outside this one .DATA string DB "Hello",13,10,"$" .CODE print: mov dx, OFFSET string ;Load location of string mov ah, 09h ;call string display function int 21h jmp exit ;go back to main module END
In this example, the symbol exit is declared public in the main module so that it can be accessed from another source module (task).
The main module also contains an external declaration of the symbol print. This declaration defines print to be a near label so that it can be accessed from the module main, even though it is assumed to be located and declared public in another source module.
A jmp instruction later in main has the label print as its destination.
The symbol print is declared public in the task module so that it may be accessed from another module (main).
The symbol exit is defined as a near label so that it can be accessed from this module, even though it is assumed to be located and declared public in the other module.
Before this program can be executed, the two source files (one containing main, the other task) must be assembled individually, then linked together using a linker.
The symbol listing for each source file shows the segment allocations.
MAIN.ASM Symbol Table Symbol Name Type Value ??DATE Text "21-05-89" ??FILENAME Text "MAIN " ??TIME Text "14:20:27" ??VERSION Number 0100 @CODE Text _TEXT @CODESIZE Text 0 @CPU Text 0101H @CURSEG Text _TEXT @DATA Text DGROUP @DATASIZE Text 0 @FILENAME Text MAIN @WORDSIZE Text 2 EXIT Near _TEXT:0008 PRINT Near ----:---- Extern START Near _TEXT:0000 Groups & Segments Bit Size Align Combine Class DGROUP Group STACK 16 0100 Para Stack STACK _DATA 16 0000 Word Public DATA _TEXT 16 000D Word Public CODE TASK.ASM Symbol Table Symbol Name Type Value ??DATE Text "21-05-89" ??FILENAME Text "TASK " ??TIME Text "14:20:14" ??VERSION Number 0100 @CODE Text _TEXT @CODESIZE Text 0 @CPU Text 0101H @CURSEG Text _TEXT @DATA Text DGROUP @DATASIZE Text 0 @FILENAME Text TASK @WORDSIZE Text 2 EXIT Near ----:---- Extern PRINT Near _TEXT:0000 STRING Byte DGROUP:0000 Groups & Segments Bit Size Align Combine Class DGROUP Group _DATA 16 0008 Word Public DATA _TEXT 16 000A Word Public CODE
The map listing form the linker clearly shows how these segments have been combined.
MAIN.MAP (Output from Linker) Start Stop Length Name Class 00000H 00017H 00018H _TEXT CODE 00018H 0001FH 00008H _DATA DATA 00020H 0011FH 00100H STACK STACK Detailed map of segments 0000:0000 000D C=CODE S=_TEXT G=(none) M=MAIN.ASM ACBP=48 0000:000E 000A C=CODE S=_TEXT G=(none) M=TASK.ASM ACBP=48 0001:0008 0000 C=DATA S=_DATA G=DGROUP M=MAIN.ASM ACBP=48 0001:0008 0008 C=DATA S=_DATA G=DGROUP M=TASK.ASM ACBP=48 0002:0000 0100 C=STACK S=STACK G=DGROUP M=MAIN.ASM ACBP=74 Address Publics by Name 0000:0008 EXIT 0000:000E PRINT Address Publics by Value 0000:0008 EXIT 0000:000E PRINT Program entry point at 0000:0000
SEGMENT DIRECTIVES
So far, 8088 programs have been implemented
using single segments with the directives
.CODE .STACK .DATA
This simplifies writing programs, but has several drawbacks.
The use of the segment directives provide the necessary controls for implementing large multiple segment programs. The programmer can specify which segments should be overlayed, combined, or stand alone.
Segment over-ride prefixs may be applied to certain instructions.
mov ax, cs:20h
obtains data from the code segment rather than the data segment.
The format for declaring a segment is,
name SEGMENT align combine_type class name ENDS
Align specifies whether the segment starts at a byte, word or paragraph (10 byte) boundary. The default is paragraph.
Combine_type specifies whether the segment is PUBLIC, COMMON, MEMORY, PRIVATE, PUBLIC or STACK.
PUBLIC The linker concatenates all segments with the same name to form a single contigous segment. The length is the sum of all the segments. COMMON The linker locates all segments with the same name at the same address (overlayed on top of each other). The length becomes the longest segment. MEMORY Same as Public PRIVATE The linker does not combine this segment with any other segment. STACK The linker concatenates all segments with the same name to form a single contiguous segment. The length is the sum of all the segments. SS is initialised to the beginning of the segment, SP to the length of the segment.
Class controls the ordering of the segments at linking time. Segments with the same class name are loaded together. A segment of class CODE would be loaded before a segment of class STACK. The class name is enclosed using single or double quotes.
An example program follows.
TITLE Segdemo stck segment para private 'STACK' db 200h dup (?) stck ends data segment byte public 'DATA' message db 'Hello there','$' data ends data2 segment byte public 'DATA2' message2 db 'Segment Data2','$' data2 ends code segment para private 'CODE' assume ds:data, ss:stck start: mov ax, seg data mov ds, ax mov ah, 9 mov dx, offset message int 21h assume ds:data2 mov ax, seg data2 mov ds, ax mov ah, 9 mov dx, offset message2 int 21h mov ax, 4c00h int 21h code ends end start
The map file for segdemo.exe is,
Start Stop Length Name Class 00000H 001FFH 00200H STCK STACK 00200H 0020BH 0000CH DATA DATA 0020CH 00219H 0000EH DATA2 DATA2 00220H 0023CH 0001DH CODE CODE Detailed map of segments 0000:0000 0200 C=STACK S=STCK G=(none) M=SEGDEMO.ASM ACBP=60 0020:0000 000C C=DATA S=DATA G=(none) M=SEGDEMO.ASM ACBP=28 0020:000C 000E C=DATA2 S=DATA2 G=(none) M=SEGDEMO.ASM ACBP=28 0022:0000 001D C=CODE S=CODE G=(none) M=SEGDEMO.ASM ACBP=60
This clearly shows the ordering (class) and concatenation of segments which are the same type.